package transclusion;

import java.util.ArrayList;
import java.util.Arrays;

import processing.core.*;
import transclusion.items.*;
import treemap.*;

public class CategoryItem extends SourceItem implements MapModel {
	MapLayout algorithm = new PivotBySplitSize();
	Mappable[] items;
	boolean contentsVisible;
	boolean layoutValid;
	float darkness;
	boolean reinvokedZoom = false;

	public CategoryItem(DAG d, CategoryItem parent, Itemable category, int level, int order) {
		super(d, parent, category, level, order);
		
		ArrayList<Itemable> children = category.orderedList();
		if( children != null ) {
			items = new Mappable[children.size()];
			int count = 0;
			for ( Itemable child : children ) {
				SourceItem newItem = null;
				if (child.isCategory())
					newItem = new CategoryItem(dag, this, child, level + 1, count);
				else
					newItem = new SourceItem(dag, this, child, level + 1, count);
				items[count++] = newItem;
				size += newItem.getSize();
			}
		} else
			// If no items found in this folder, create a dummy array so that
			// items will not be null, which will ensure that items.length will
			// return 0 rather than causing a NullPointerException.
			items = new Mappable[0];				
	}

	@Override
	void updateColors() {
		super.updateColors();

		for (int i = 0; i < items.length; i++) {
			SourceItem fi = (SourceItem) items[i];
			fi.updateColors();
		}
	}

	void checkLayout() {
		if (!layoutValid) {
			if (getItemCount() != 0) {
				algorithm.layout(this, bounds);
			}
			layoutValid = true;
		}
	}
	
	@Override
	boolean mouseClicked() {
		if (mouseInside()) {
			if (contentsVisible) {
				// Pass the mouse press to the child items
				for (int i = 0; i < items.length; i++) {
					SourceItem fi = (SourceItem) items[i];
					if (fi.mouseClicked())
						return true;
				}
			} else { // not opened				
				if (papplet.mouseButton == PApplet.LEFT)
					open();
				else if (papplet.mouseButton == PApplet.RIGHT)
					close();			
				return true;
			}
		}
		return false;
	}
	
	@Override
	void open() {	
		if (parent == ((UniverseVisualization) papplet).zoomItem) {
			showContents();
		} else {
			parent.zoomIn();			
		}
	}

	// Zoom to the parent's boundary, zooming out from this item
	void zoomOut() {
		if (parent != null) {
			// Close contents of any opened children
			for (int i = 0; i < items.length; i++) {
				if (items[i] instanceof CategoryItem) {
					((CategoryItem) items[i]).hideContents();
				}
			}
			parent.zoomIn();
		}
	}

	void zoomIn() {
		if (((UniverseVisualization) papplet).zoomItem == this)
			reinvokedZoom = true;
		else
			reinvokedZoom = false;
		((UniverseVisualization) papplet).zoomItem = this;
		//debug
		//PApplet.println("zoomItem is: " + name);
		((UniverseVisualization) papplet).zoomBounds.target(x, y, w, h);		
	}

	void showContents() {
		contentsVisible = true;
	}

	void hideContents() {
		// Prevent the user from closing the root level
		if (parent != null)
			contentsVisible = false;
	}

	@Override
	public void draw() {
		checkLayout();
		calcBox();

		if (contentsVisible) {
			for (int i = 0; i < items.length; i++) {
				items[i].draw();
			}
		} else {
			super.draw();
		}

		if (contentsVisible) {
			if (mouseInside()) {
				if (parent == ((UniverseVisualization) papplet).zoomItem) {
					((UniverseVisualization) papplet).taggedItem = this;
				}
			}
		}
		if (mouseInside()) {
			darkness *= 0.05;
		} else {
			darkness += (150 - darkness) * 0.05;
		}
		if (parent == ((UniverseVisualization) papplet).zoomItem) {
			papplet.colorMode(PApplet.RGB, 255);
			papplet.fill(0, darkness);
			papplet.rect(boxLeft, boxTop, boxRight, boxBottom);
		}
	}

	@Override
	void drawTitle() {
		if (!contentsVisible) {
			super.drawTitle();
		}
	}

	void drawTag() {
		float boxHeight = papplet.textAscent() + textPadding * 2;

		if (boxBottom - boxTop > boxHeight * 2) {
			// if the height of the box is at least twice the height of the tag,
			// draw the tag inside the box itself
			papplet.fill(0, 128);
			papplet.rect(boxLeft, boxTop, boxRight, boxTop + boxHeight);
			papplet.fill(255);
			papplet.textAlign(PApplet.LEFT, PApplet.TOP);
			papplet.text(name, boxLeft + textPadding, boxTop + textPadding);

		} else if (boxTop > boxHeight) {
			// if there's enough room to draw above, draw it there
			papplet.fill(0, 128);
			papplet.rect(boxLeft, boxTop - boxHeight, boxRight, boxTop);
			papplet.fill(255);
			papplet.text(name, boxLeft + textPadding, boxTop - textPadding);

		} else if (boxBottom + boxHeight < papplet.height) {
			// otherwise draw the tag below
			papplet.fill(0, 128);
			papplet.rect(boxLeft, boxBottom, boxRight, boxBottom + boxHeight);
			papplet.fill(255);
			papplet.textAlign(PApplet.LEFT, PApplet.TOP);
			papplet.text(name, boxLeft + textPadding, boxBottom + textPadding);
		}
	}

	public Mappable[] getItems() {
		return items;
	}
	
	public ArrayList<Mappable> getArrayItems() {
		return new ArrayList<Mappable>(Arrays.asList(items));
	}

	int getItemCount() {
		return items.length;
	}
}
